home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -serious- / programming / other / mesa / mesa-aux / src-aux.aos / shapes.c < prev    next >
C/C++ Source or Header  |  2000-02-23  |  28KB  |  1,189 lines

  1. /*
  2.  * shapes.c 
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <math.h>
  8. #include <GL/gl.h>
  9. #include <GL/glu.h>
  10. #include <GL/glaux.h>
  11. #include "3d.h"
  12. #include "shapes.h"
  13.  
  14. #define SPHEREWIRE    0
  15. #define CUBEWIRE    1
  16. #define BOXWIRE        2
  17. #define TORUSWIRE    3
  18. #define CYLINDERWIRE    4
  19. #define ICOSAWIRE    5
  20. #define OCTAWIRE    6
  21. #define TETRAWIRE    7
  22. #define DODECAWIRE    8
  23. #define CONEWIRE    9
  24. #define SPHERESOLID    10
  25. #define CUBESOLID    11
  26. #define BOXSOLID    12
  27. #define TORUSSOLID    13
  28. #define CYLINDERSOLID    14
  29. #define ICOSASOLID    15
  30. #define OCTASOLID    16
  31. #define TETRASOLID    17
  32. #define DODECASOLID    18
  33. #define CONESOLID    19
  34.  
  35. #ifndef PI
  36. #define PI 3.1415926535897
  37. #endif
  38.  
  39. /*
  40.  * array of linked lists--used to keep track of display lists 
  41.  * *    for each different type of geometric object.
  42.  */
  43. static MODELPTR lists[25] =
  44. {
  45.   NULL, NULL, NULL, NULL, NULL,
  46.   NULL, NULL, NULL, NULL, NULL,
  47.   NULL, NULL, NULL, NULL, NULL,
  48.   NULL, NULL, NULL, NULL, NULL,
  49.   NULL, NULL, NULL, NULL, NULL
  50. };
  51.  
  52. GLuint findList(int lindex, GLdouble * paramArray, int size);
  53. int compareParams(GLdouble * oneArray, GLdouble * twoArray, int size);
  54. GLuint makeModelPtr(int lindex, GLdouble * sizeArray, int count);
  55.  
  56. static void drawbox(GLdouble, GLdouble, GLdouble,
  57.             GLdouble, GLdouble, GLdouble, GLenum);
  58. static void doughnut(GLdouble, GLdouble, GLint, GLint, GLenum);
  59. static void icosahedron(GLdouble *, GLdouble, GLenum);
  60. static void octahedron(GLdouble *, GLdouble, GLenum);
  61. static void tetrahedron(GLdouble *, GLdouble, GLenum);
  62. static void subdivide(int, GLdouble *, GLdouble *, GLdouble *,
  63.               GLdouble *, GLdouble, GLenum, int);
  64. static void drawtriangle(int, int, int,
  65.              GLdouble *, GLdouble, GLenum, int);
  66. static void recorditem(GLdouble *, GLdouble *, GLdouble *,
  67.                GLdouble *, GLdouble, GLenum, int);
  68. static void initdodec(void);
  69. static void dodecahedron(GLdouble *, GLdouble, GLenum);
  70. static void pentagon(int, int, int, int, int, GLenum);
  71.  
  72. /*
  73.  * Render wire frame or solid sphere.  If no display list with
  74.  * *  the current model size exists, create a new display list.
  75.  */
  76. void auxWireSphere(GLdouble radius)
  77. {
  78.   GLUquadricObj *quadObj;
  79.   GLdouble *sizeArray;
  80.   GLuint displayList;
  81.  
  82.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  83.   *sizeArray = radius;
  84.   displayList = findList(SPHEREWIRE, sizeArray, 1);
  85.  
  86.   if (displayList == 0) {
  87.     glNewList(makeModelPtr(SPHEREWIRE, sizeArray, 1),
  88.           GL_COMPILE_AND_EXECUTE);
  89.     quadObj = gluNewQuadric();
  90.     gluQuadricDrawStyle(quadObj, GLU_LINE);
  91.     gluSphere(quadObj, radius, 16, 16);
  92.     glEndList();
  93.   }
  94.   else {
  95.     glCallList(displayList);
  96.     free(sizeArray);
  97.   }
  98. }
  99.  
  100. void auxSolidSphere(GLdouble radius)
  101. {
  102.   GLUquadricObj *quadObj;
  103.   GLdouble *sizeArray;
  104.   GLuint displayList;
  105.  
  106.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  107.   *sizeArray = radius;
  108.   displayList = findList(SPHERESOLID, sizeArray, 1);
  109.  
  110.   if (displayList == 0) {
  111.     glNewList(makeModelPtr(SPHERESOLID, sizeArray, 1),
  112.           GL_COMPILE_AND_EXECUTE);
  113.     quadObj = gluNewQuadric();
  114.     gluQuadricDrawStyle(quadObj, GLU_FILL);
  115.     gluQuadricNormals(quadObj, GLU_SMOOTH);
  116.     gluSphere(quadObj, radius, 16, 16);
  117.     glEndList();
  118.   }
  119.   else {
  120.     glCallList(displayList);
  121.     free(sizeArray);
  122.   }
  123. }
  124.  
  125. /*
  126.  * Render wire frame or solid cube.  If no display list with
  127.  * *  the current model size exists, create a new display list.
  128.  */
  129. void auxWireCube(GLdouble size)
  130. {
  131.   GLdouble *sizeArray;
  132.   GLuint displayList;
  133.  
  134.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  135.   *sizeArray = size;
  136.   displayList = findList(CUBEWIRE, sizeArray, 1);
  137.  
  138.   if (displayList == 0) {
  139.     glNewList(makeModelPtr(CUBEWIRE, sizeArray, 1),
  140.           GL_COMPILE_AND_EXECUTE);
  141.     drawbox(-size / 2., size / 2., -size / 2., size / 2.,
  142.         -size / 2., size / 2., GL_LINE_LOOP);
  143.     glEndList();
  144.   }
  145.   else {
  146.     glCallList(displayList);
  147.     free(sizeArray);
  148.   }
  149. }
  150.  
  151. void auxSolidCube(GLdouble size)
  152. {
  153.   GLdouble *sizeArray;
  154.   GLuint displayList;
  155.  
  156.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  157.   *sizeArray = size;
  158.   displayList = findList(CUBESOLID, sizeArray, 1);
  159.  
  160.   if (displayList == 0) {
  161.     glNewList(makeModelPtr(CUBESOLID, sizeArray, 1),
  162.           GL_COMPILE_AND_EXECUTE);
  163.     drawbox(-size / 2., size / 2., -size / 2., size / 2.,
  164.         -size / 2., size / 2., GL_QUADS);
  165.     glEndList();
  166.   }
  167.   else {
  168.     glCallList(displayList);
  169.     free(sizeArray);
  170.   }
  171. }
  172.  
  173. /*
  174.  * Render wire frame or solid cube.  If no display list with
  175.  * *  the current model size exists, create a new display list.
  176.  */
  177. void auxWireBox(GLdouble width, GLdouble height, GLdouble depth)
  178. {
  179.   GLdouble *sizeArray, *tmp;
  180.   GLuint displayList;
  181.  
  182.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 3);
  183.   tmp = sizeArray;
  184.   *tmp++ = width;
  185.   *tmp++ = height;
  186.   *tmp++ = depth;
  187.   displayList = findList(BOXWIRE, sizeArray, 3);
  188.  
  189.   if (displayList == 0) {
  190.     glNewList(makeModelPtr(BOXWIRE, sizeArray, 3),
  191.           GL_COMPILE_AND_EXECUTE);
  192.     drawbox(-width / 2., width / 2., -height / 2., height / 2.,
  193.         -depth / 2., depth / 2., GL_LINE_LOOP);
  194.     glEndList();
  195.   }
  196.   else {
  197.     glCallList(displayList);
  198.     free(sizeArray);
  199.   }
  200. }
  201.  
  202. void auxSolidBox(GLdouble width, GLdouble height, GLdouble depth)
  203. {
  204.   GLdouble *sizeArray, *tmp;
  205.   GLuint displayList;
  206.  
  207.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 3);
  208.   tmp = sizeArray;
  209.   *tmp++ = width;
  210.   *tmp++ = height;
  211.   *tmp++ = depth;
  212.   displayList = findList(BOXSOLID, sizeArray, 3);
  213.  
  214.   if (displayList == 0) {
  215.     glNewList(makeModelPtr(BOXSOLID, sizeArray, 3),
  216.           GL_COMPILE_AND_EXECUTE);
  217.     drawbox(-width / 2., width / 2., -height / 2., height / 2.,
  218.         -depth / 2., depth / 2., GL_QUADS);
  219.     glEndList();
  220.   }
  221.   else {
  222.     glCallList(displayList);
  223.     free(sizeArray);
  224.   }
  225. }
  226.  
  227. /*
  228.  * Render wire frame or solid tori.  If no display list with
  229.  * *  the current model size exists, create a new display list.
  230.  */
  231. void auxWireTorus(GLdouble innerRadius, GLdouble outerRadius)
  232. {
  233.   GLdouble *sizeArray, *tmp;
  234.   GLuint displayList;
  235.  
  236.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  237.   tmp = sizeArray;
  238.   *tmp++ = innerRadius;
  239.   *tmp++ = outerRadius;
  240.   displayList = findList(TORUSWIRE, sizeArray, 2);
  241.  
  242.   if (displayList == 0) {
  243.     glNewList(makeModelPtr(TORUSWIRE, sizeArray, 2),
  244.           GL_COMPILE_AND_EXECUTE);
  245.     doughnut(innerRadius, outerRadius, 5, 10, GL_LINE_LOOP);
  246.     glEndList();
  247.   }
  248.   else {
  249.     glCallList(displayList);
  250.     free(sizeArray);
  251.   }
  252. }
  253.  
  254. void auxSolidTorus(GLdouble innerRadius, GLdouble outerRadius)
  255. {
  256.   GLdouble *sizeArray, *tmp;
  257.   GLuint displayList;
  258.  
  259.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  260.   tmp = sizeArray;
  261.   *tmp++ = innerRadius;
  262.   *tmp++ = outerRadius;
  263.   displayList = findList(TORUSSOLID, sizeArray, 2);
  264.  
  265.   if (displayList == 0) {
  266.     glNewList(makeModelPtr(TORUSSOLID, sizeArray, 2),
  267.           GL_COMPILE_AND_EXECUTE);
  268.     doughnut(innerRadius, outerRadius, 8, 15, GL_QUADS);
  269.     glEndList();
  270.   }
  271.   else {
  272.     glCallList(displayList);
  273.     free(sizeArray);
  274.   }
  275. }
  276.  
  277. /*
  278.  * Render wire frame or solid cylinders.  If no display list with
  279.  * *  the current model size exists, create a new display list.
  280.  */
  281. void auxWireCylinder(GLdouble radius, GLdouble height)
  282. {
  283.   GLUquadricObj *quadObj;
  284.   GLdouble *sizeArray, *tmp;
  285.   GLuint displayList;
  286.  
  287.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  288.   tmp = sizeArray;
  289.   *tmp++ = radius;
  290.   *tmp++ = height;
  291.   displayList = findList(CYLINDERWIRE, sizeArray, 2);
  292.  
  293.   if (displayList == 0) {
  294.     glNewList(makeModelPtr(CYLINDERWIRE, sizeArray, 2),
  295.           GL_COMPILE_AND_EXECUTE);
  296.     glPushMatrix();
  297.     glRotatef(90.0, 1.0, 0.0, 0.0);
  298.     glTranslatef(0.0, 0.0, -1.0);
  299.     quadObj = gluNewQuadric();
  300.     gluQuadricDrawStyle(quadObj, GLU_LINE);
  301.     gluCylinder(quadObj, radius, radius, height, 12, 2);
  302.     glPopMatrix();
  303.     glEndList();
  304.   }
  305.   else {
  306.     glCallList(displayList);
  307.     free(sizeArray);
  308.   }
  309. }
  310.  
  311. void auxSolidCylinder(GLdouble radius, GLdouble height)
  312. {
  313.   GLUquadricObj *quadObj;
  314.   GLdouble *sizeArray, *tmp;
  315.   GLuint displayList;
  316.  
  317.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  318.   tmp = sizeArray;
  319.   *tmp++ = radius;
  320.   *tmp++ = height;
  321.   displayList = findList(CYLINDERSOLID, sizeArray, 2);
  322.  
  323.   if (displayList == 0) {
  324.     glNewList(makeModelPtr(CYLINDERSOLID, sizeArray, 2),
  325.           GL_COMPILE_AND_EXECUTE);
  326.     glPushMatrix();
  327.     glRotatef(90.0, 1.0, 0.0, 0.0);
  328.     glTranslatef(0.0, 0.0, -1.0);
  329.     quadObj = gluNewQuadric();
  330.     gluQuadricDrawStyle(quadObj, GLU_FILL);
  331.     gluQuadricNormals(quadObj, GLU_SMOOTH);
  332.     gluCylinder(quadObj, radius, radius, height, 12, 2);
  333.     glPopMatrix();
  334.     glEndList();
  335.   }
  336.   else {
  337.     glCallList(displayList);
  338.     free(sizeArray);
  339.   }
  340. }
  341.  
  342. /*
  343.  * Render wire frame or solid icosahedra.  If no display list with
  344.  * *  the current model size exists, create a new display list.
  345.  */
  346. void auxWireIcosahedron(GLdouble radius)
  347. {
  348.   GLdouble *sizeArray;
  349.   GLuint displayList;
  350.   static GLdouble center[3] =
  351.   {0.0, 0.0, 0.0};
  352.  
  353.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  354.   *sizeArray = radius;
  355.   displayList = findList(ICOSAWIRE, sizeArray, 1);
  356.  
  357.   if (displayList == 0) {
  358.     glNewList(makeModelPtr(ICOSAWIRE, sizeArray, 1),
  359.           GL_COMPILE_AND_EXECUTE);
  360.     icosahedron(center, radius, GL_LINE_LOOP);
  361.     glEndList();
  362.   }
  363.   else {
  364.     glCallList(displayList);
  365.     free(sizeArray);
  366.   }
  367. }
  368.  
  369. void auxSolidIcosahedron(GLdouble radius)
  370. {
  371.   GLdouble *sizeArray;
  372.   GLuint displayList;
  373.   static GLdouble center[3] =
  374.   {0.0, 0.0, 0.0};
  375.  
  376.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  377.   *sizeArray = radius;
  378.   displayList = findList(ICOSASOLID, sizeArray, 1);
  379.  
  380.   if (displayList == 0) {
  381.     glNewList(makeModelPtr(ICOSASOLID, sizeArray, 1),
  382.           GL_COMPILE_AND_EXECUTE);
  383.     icosahedron(center, radius, GL_TRIANGLES);
  384.     glEndList();
  385.   }
  386.   else {
  387.     glCallList(displayList);
  388.     free(sizeArray);
  389.   }
  390. }
  391.  
  392. /*
  393.  * Render wire frame or solid octahedra.  If no display list with
  394.  * *  the current model size exists, create a new display list.
  395.  */
  396. void auxWireOctahedron(GLdouble radius)
  397. {
  398.   GLdouble *sizeArray;
  399.   GLuint displayList;
  400.   static GLdouble center[3] =
  401.   {0.0, 0.0, 0.0};
  402.  
  403.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  404.   *sizeArray = radius;
  405.   displayList = findList(OCTAWIRE, sizeArray, 1);
  406.  
  407.   if (displayList == 0) {
  408.     glNewList(makeModelPtr(OCTAWIRE, sizeArray, 1),
  409.           GL_COMPILE_AND_EXECUTE);
  410.     octahedron(center, radius, GL_LINE_LOOP);
  411.     glEndList();
  412.   }
  413.   else {
  414.     glCallList(displayList);
  415.     free(sizeArray);
  416.   }
  417. }
  418.  
  419. void auxSolidOctahedron(GLdouble radius)
  420. {
  421.   GLdouble *sizeArray;
  422.   GLuint displayList;
  423.   static GLdouble center[3] =
  424.   {0.0, 0.0, 0.0};
  425.  
  426.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  427.   *sizeArray = radius;
  428.   displayList = findList(OCTASOLID, sizeArray, 1);
  429.  
  430.   if (displayList == 0) {
  431.     glNewList(makeModelPtr(OCTASOLID, sizeArray, 1),
  432.           GL_COMPILE_AND_EXECUTE);
  433.     octahedron(center, radius, GL_TRIANGLES);
  434.     glEndList();
  435.   }
  436.   else {
  437.     glCallList(displayList);
  438.     free(sizeArray);
  439.   }
  440. }
  441.  
  442. /*
  443.  * Render wire frame or solid tetrahedra.  If no display list with
  444.  * *  the current model size exists, create a new display list.
  445.  */
  446. void auxWireTetrahedron(GLdouble radius)
  447. {
  448.   GLdouble *sizeArray;
  449.   GLuint displayList;
  450.   static GLdouble center[3] =
  451.   {0.0, 0.0, 0.0};
  452.  
  453.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  454.   *sizeArray = radius;
  455.   displayList = findList(TETRAWIRE, sizeArray, 1);
  456.  
  457.   if (displayList == 0) {
  458.     glNewList(makeModelPtr(TETRAWIRE, sizeArray, 1),
  459.           GL_COMPILE_AND_EXECUTE);
  460.     tetrahedron(center, radius, GL_LINE_LOOP);
  461.     glEndList();
  462.   }
  463.   else {
  464.     glCallList(displayList);
  465.     free(sizeArray);
  466.   }
  467. }
  468.  
  469. void auxSolidTetrahedron(GLdouble radius)
  470. {
  471.   GLdouble *sizeArray;
  472.   GLuint displayList;
  473.   static GLdouble center[3] =
  474.   {0.0, 0.0, 0.0};
  475.  
  476.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  477.   *sizeArray = radius;
  478.   displayList = findList(TETRASOLID, sizeArray, 1);
  479.  
  480.   if (displayList == 0) {
  481.     glNewList(makeModelPtr(TETRASOLID, sizeArray, 1),
  482.           GL_COMPILE_AND_EXECUTE);
  483.     tetrahedron(center, radius, GL_TRIANGLES);
  484.     glEndList();
  485.   }
  486.   else {
  487.     glCallList(displayList);
  488.     free(sizeArray);
  489.   }
  490. }
  491.  
  492. /*
  493.  * Render wire frame or solid dodecahedra.  If no display list with
  494.  * *  the current model size exists, create a new display list.
  495.  */
  496. void auxWireDodecahedron(GLdouble radius)
  497. {
  498.   GLdouble *sizeArray;
  499.   GLuint displayList;
  500.   static GLdouble center[3] =
  501.   {0.0, 0.0, 0.0};
  502.  
  503.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  504.   *sizeArray = radius;
  505.   displayList = findList(DODECAWIRE, sizeArray, 1);
  506.  
  507.   if (displayList == 0) {
  508.     glNewList(makeModelPtr(DODECAWIRE, sizeArray, 1),
  509.           GL_COMPILE_AND_EXECUTE);
  510.     dodecahedron(center, radius / 1.73, GL_LINE_LOOP);
  511.     glEndList();
  512.   }
  513.   else {
  514.     glCallList(displayList);
  515.     free(sizeArray);
  516.   }
  517. }
  518.  
  519. void auxSolidDodecahedron(GLdouble radius)
  520. {
  521.   GLdouble *sizeArray;
  522.   GLuint displayList;
  523.   static GLdouble center[3] =
  524.   {0.0, 0.0, 0.0};
  525.  
  526.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 1);
  527.   *sizeArray = radius;
  528.   displayList = findList(DODECASOLID, sizeArray, 1);
  529.  
  530.   if (displayList == 0) {
  531.     glNewList(makeModelPtr(DODECASOLID, sizeArray, 1),
  532.           GL_COMPILE_AND_EXECUTE);
  533.     dodecahedron(center, radius / 1.73, GL_TRIANGLE_FAN);
  534.     glEndList();
  535.   }
  536.   else {
  537.     glCallList(displayList);
  538.     free(sizeArray);
  539.   }
  540. }
  541.  
  542. /*
  543.  * Render wire frame or solid cones.  If no display list with
  544.  * *  the current model size exists, create a new display list.
  545.  */
  546. void auxWireCone(GLdouble base, GLdouble height)
  547. {
  548.   GLUquadricObj *quadObj;
  549.   GLdouble *sizeArray, *tmp;
  550.   GLuint displayList;
  551.  
  552.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  553.   tmp = sizeArray;
  554.   *tmp++ = base;
  555.   *tmp++ = height;
  556.   displayList = findList(CONEWIRE, sizeArray, 2);
  557.  
  558.   if (displayList == 0) {
  559.     glNewList(makeModelPtr(CONEWIRE, sizeArray, 2),
  560.           GL_COMPILE_AND_EXECUTE);
  561.     quadObj = gluNewQuadric();
  562.     gluQuadricDrawStyle(quadObj, GLU_LINE);
  563.     gluCylinder(quadObj, base, 0.0, height, 15, 10);
  564.     glEndList();
  565.   }
  566.   else {
  567.     glCallList(displayList);
  568.     free(sizeArray);
  569.   }
  570. }
  571.  
  572. void auxSolidCone(GLdouble base, GLdouble height)
  573. {
  574.   GLUquadricObj *quadObj;
  575.   GLdouble *sizeArray, *tmp;
  576.   GLuint displayList;
  577.  
  578.   sizeArray = (GLdouble *) malloc(sizeof(GLdouble) * 2);
  579.   tmp = sizeArray;
  580.   *tmp++ = base;
  581.   *tmp++ = height;
  582.   displayList = findList(CONEWIRE, sizeArray, 2);
  583.  
  584.   if (displayList == 0) {
  585.     glNewList(makeModelPtr(CONEWIRE, sizeArray, 2),
  586.           GL_COMPILE_AND_EXECUTE);
  587.     quadObj = gluNewQuadric();
  588.     gluQuadricDrawStyle(quadObj, GLU_FILL);
  589.     gluQuadricNormals(quadObj, GLU_SMOOTH);
  590.     gluCylinder(quadObj, base, 0.0, height, 15, 10);
  591.     glEndList();
  592.   }
  593.   else {
  594.     glCallList(displayList);
  595.     free(sizeArray);
  596.   }
  597. }
  598.  
  599. /*
  600.  * Routines to build 3 dimensional solids, including:
  601.  * *
  602.  * * drawbox, doughnut, icosahedron, 
  603.  * * octahedron, tetrahedron, dodecahedron.
  604.  */
  605.  
  606. /*
  607.  * drawbox:
  608.  * *
  609.  * * draws a rectangular box with the given x, y, and z ranges.  
  610.  * * The box is axis-aligned.
  611.  */
  612. static void drawbox(GLdouble x0, GLdouble x1, GLdouble y0, GLdouble y1,
  613.             GLdouble z0, GLdouble z1, GLenum type)
  614. {
  615.   static const GLdouble n[6][3] =
  616.   {
  617.     {-1.0, 0.0, 0.0},
  618.     {0.0, 1.0, 0.0},
  619.     {1.0, 0.0, 0.0},
  620.     {0.0, -1.0, 0.0},
  621.     {0.0, 0.0, 1.0},
  622.     {0.0, 0.0, -1.0}
  623.   };
  624.   static const GLint faces[6][4] =
  625.   {
  626.     {0, 1, 2, 3},
  627.     {3, 2, 6, 7},
  628.     {7, 6, 5, 4},
  629.     {4, 5, 1, 0},
  630.     {5, 6, 2, 1},
  631.     {7, 4, 0, 3}
  632.   };
  633.   GLdouble v[8][3], tmp;
  634.   GLint i;
  635.  
  636.   if (x0 > x1) {
  637.     tmp = x0;
  638.     x0 = x1;
  639.     x1 = tmp;
  640.   }
  641.   if (y0 > y1) {
  642.     tmp = y0;
  643.     y0 = y1;
  644.     y1 = tmp;
  645.   }
  646.   if (z0 > z1) {
  647.     tmp = z0;
  648.     z0 = z1;
  649.     z1 = tmp;
  650.   }
  651.   v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
  652.   v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
  653.   v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
  654.   v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
  655.   v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
  656.   v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;
  657.  
  658.   for (i = 0; i < 6; i++) {
  659.     glBegin(type);
  660.     glNormal3dv(&n[i][0]);
  661.     glVertex3dv(&v[faces[i][0]][0]);
  662.     glNormal3dv(&n[i][0]);
  663.     glVertex3dv(&v[faces[i][1]][0]);
  664.     glNormal3dv(&n[i][0]);
  665.     glVertex3dv(&v[faces[i][2]][0]);
  666.     glNormal3dv(&n[i][0]);
  667.     glVertex3dv(&v[faces[i][3]][0]);
  668.     glEnd();
  669.   }
  670. }
  671.  
  672. /*
  673.  * doughnut:
  674.  * *
  675.  * * draws a doughnut, centered at (0, 0, 0) whose axis is aligned with
  676.  * * the z-axis.  The doughnut's major radius is R, and minor radius is r.
  677.  */
  678.  
  679. static void doughnut(GLdouble r, GLdouble R, GLint nsides, GLint rings, GLenum type)
  680. {
  681.   int i, j;
  682.   GLdouble theta, phi, theta1, phi1;
  683.   GLdouble p0[03], p1[3], p2[3], p3[3];
  684.   GLdouble n0[3], n1[3], n2[3], n3[3];
  685.  
  686.   for (i = 0; i < rings; i++) {
  687.     theta = (GLdouble) i *2.0 * PI / rings;
  688.  
  689.     theta1 = (GLdouble) (i + 1) * 2.0 * PI / rings;
  690.     for (j = 0; j < nsides; j++) {
  691.       phi = (GLdouble) j *2.0 * PI / nsides;
  692.  
  693.       phi1 = (GLdouble) (j + 1) * 2.0 * PI / nsides;
  694.  
  695.       p0[0] = cos(theta) * (R + r * cos(phi));
  696.       p0[1] = -sin(theta) * (R + r * cos(phi));
  697.       p0[2] = r * sin(phi);
  698.  
  699.       p1[0] = cos(theta1) * (R + r * cos(phi));
  700.       p1[1] = -sin(theta1) * (R + r * cos(phi));
  701.       p1[2] = r * sin(phi);
  702.  
  703.       p2[0] = cos(theta1) * (R + r * cos(phi1));
  704.       p2[1] = -sin(theta1) * (R + r * cos(phi1));
  705.       p2[2] = r * sin(phi1);
  706.  
  707.       p3[0] = cos(theta) * (R + r * cos(phi1));
  708.       p3[1] = -sin(theta) * (R + r * cos(phi1));
  709.       p3[2] = r * sin(phi1);
  710.  
  711.       n0[0] = cos(theta) * (cos(phi));
  712.       n0[1] = -sin(theta) * (cos(phi));
  713.       n0[2] = sin(phi);
  714.  
  715.       n1[0] = cos(theta1) * (cos(phi));
  716.       n1[1] = -sin(theta1) * (cos(phi));
  717.       n1[2] = sin(phi);
  718.  
  719.       n2[0] = cos(theta1) * (cos(phi1));
  720.       n2[1] = -sin(theta1) * (cos(phi1));
  721.       n2[2] = sin(phi1);
  722.  
  723.       n3[0] = cos(theta) * (cos(phi1));
  724.       n3[1] = -sin(theta) * (cos(phi1));
  725.       n3[2] = sin(phi1);
  726.  
  727.       m_xformpt(p0, p0, n0, n0);
  728.       m_xformpt(p1, p1, n1, n1);
  729.       m_xformpt(p2, p2, n2, n2);
  730.       m_xformpt(p3, p3, n3, n3);
  731.  
  732.       glBegin(type);
  733.       glNormal3dv(n3);
  734.       glVertex3dv(p3);
  735.       glNormal3dv(n2);
  736.       glVertex3dv(p2);
  737.       glNormal3dv(n1);
  738.       glVertex3dv(p1);
  739.       glNormal3dv(n0);
  740.       glVertex3dv(p0);
  741.       glEnd();
  742.     }
  743.   }
  744. }
  745.  
  746. /*
  747.  * octahedron data: The octahedron produced is centered 
  748.  * * at the origin and has radius 1.0 
  749.  */
  750. static const GLdouble odata[6][3] =
  751. {
  752.   {1.0, 0.0, 0.0},
  753.   {-1.0, 0.0, 0.0},
  754.   {0.0, 1.0, 0.0},
  755.   {0.0, -1.0, 0.0},
  756.   {0.0, 0.0, 1.0},
  757.   {0.0, 0.0, -1.0}
  758. };
  759.  
  760. static const int ondex[8][3] =
  761. {
  762.   {0, 4, 2},
  763.   {1, 2, 4},
  764.   {0, 3, 4},
  765.   {1, 4, 3},
  766.   {0, 2, 5},
  767.   {1, 5, 2},
  768.   {0, 5, 3},
  769.   {1, 3, 5}
  770. };
  771.  
  772. /*
  773.  * tetrahedron data: 
  774.  */
  775.  
  776. #define T    1.73205080756887729
  777.  
  778. static const GLdouble tdata[4][3] =
  779. {
  780.   {T, T, T},
  781.   {T, -T, -T},
  782.   {-T, T, -T},
  783.   {-T, -T, T}
  784. };
  785.  
  786. static const int tndex[4][3] =
  787. {
  788.   {0, 1, 3},
  789.   {2, 1, 0},
  790.   {3, 2, 0},
  791.   {1, 2, 3}
  792. };
  793.  
  794. /*
  795.  * icosahedron data: These numbers are rigged to 
  796.  * * make an icosahedron of radius 1.0 
  797.  */
  798.  
  799. #define X .525731112119133606
  800. #define Z .850650808352039932
  801.  
  802. static const GLdouble idata[12][3] =
  803. {
  804.   {-X, 0.0, Z},
  805.   {X, 0.0, Z},
  806.   {-X, 0.0, -Z},
  807.   {X, 0.0, -Z},
  808.   {0.0, Z, X},
  809.   {0.0, Z, -X},
  810.   {0.0, -Z, X},
  811.   {0.0, -Z, -X},
  812.   {Z, X, 0.0},
  813.   {-Z, X, 0.0},
  814.   {Z, -X, 0.0},
  815.   {-Z, -X, 0.0},
  816. };
  817.  
  818. static const int iindex[20][3] =
  819. {
  820.   {0, 4, 1},
  821.   {0, 9, 4},
  822.   {9, 5, 4},
  823.   {4, 5, 8},
  824.   {4, 8, 1},
  825.   {8, 10, 1},
  826.   {8, 3, 10},
  827.   {5, 3, 8},
  828.   {5, 2, 3},
  829.   {2, 7, 3},
  830.   {7, 10, 3},
  831.   {7, 6, 10},
  832.   {7, 11, 6},
  833.   {11, 0, 6},
  834.   {0, 1, 6},
  835.   {6, 1, 10},
  836.   {9, 0, 11},
  837.   {9, 11, 2},
  838.   {9, 2, 5},
  839.   {7, 2, 11},
  840. };
  841.  
  842. /*
  843.  * icosahedron:
  844.  * *
  845.  * * Draws an icosahedron with center at p0 having the
  846.  * * given radius.
  847.  */
  848.  
  849. static void icosahedron(GLdouble p0[3], GLdouble radius, GLenum shadeType)
  850. {
  851.   int i;
  852.  
  853.   for (i = 0; i < 20; i++)
  854.     drawtriangle(i, 0, 1, p0, radius, shadeType, 0);
  855. }
  856.  
  857. /*
  858.  * octahedron:
  859.  * *
  860.  * * Draws an octahedron with center at p0 having the
  861.  * * given radius.
  862.  */
  863. static void octahedron(GLdouble p0[3], GLdouble radius, GLenum shadeType)
  864. {
  865.   int i;
  866.  
  867.   for (i = 0; i < 8; i++)
  868.     drawtriangle(i, 1, 1, p0, radius, shadeType, 0);
  869. }
  870.  
  871. /*
  872.  * tetrahedron:
  873.  * *
  874.  * * Draws an tetrahedron with center at p0 having the
  875.  * * given radius.
  876.  */
  877.  
  878. static void tetrahedron(GLdouble p0[3], GLdouble radius, GLenum shadeType)
  879. {
  880.   int i;
  881.  
  882.   for (i = 0; i < 4; i++)
  883.     drawtriangle(i, 2, 1, p0, radius, shadeType, 0);
  884. }
  885.  
  886. static void subdivide(int depth, GLdouble * v0, GLdouble * v1, GLdouble * v2,
  887.           GLdouble p0[3], GLdouble radius, GLenum shadeType, int avnormal)
  888. {
  889.   GLdouble w0[3], w1[3], w2[3];
  890.   GLdouble l;
  891.   int i, j, k, n;
  892.  
  893.   for (i = 0; i < depth; i++)
  894.     for (j = 0; i + j < depth; j++) {
  895.       k = depth - i - j;
  896.       for (n = 0; n < 3; n++) {
  897.     w0[n] = (i * v0[n] + j * v1[n] + k * v2[n]) / depth;
  898.     w1[n] = ((i + 1) * v0[n] + j * v1[n] + (k - 1) * v2[n]) / depth;
  899.     w2[n] = (i * v0[n] + (j + 1) * v1[n] + (k - 1) * v2[n]) / depth;
  900.       }
  901.       l = sqrt(w0[0] * w0[0] + w0[1] * w0[1] + w0[2] * w0[2]);
  902.       w0[0] /= l;
  903.       w0[1] /= l;
  904.       w0[2] /= l;
  905.       l = sqrt(w1[0] * w1[0] + w1[1] * w1[1] + w1[2] * w1[2]);
  906.       w1[0] /= l;
  907.       w1[1] /= l;
  908.       w1[2] /= l;
  909.       l = sqrt(w2[0] * w2[0] + w2[1] * w2[1] + w2[2] * w2[2]);
  910.       w2[0] /= l;
  911.       w2[1] /= l;
  912.       w2[2] /= l;
  913.       recorditem(w1, w0, w2, p0, radius, shadeType, avnormal);
  914.     }
  915.   for (i = 0; i < depth - 1; i++)
  916.     for (j = 0; i + j < depth - 1; j++) {
  917.       k = depth - i - j;
  918.       for (n = 0; n < 3; n++) {
  919.     w0[n] = ((i + 1) * v0[n] + (j + 1) * v1[n] + (k - 2) * v2[n]) / depth;
  920.     w1[n] = ((i + 1) * v0[n] + j * v1[n] + (k - 1) * v2[n]) / depth;
  921.     w2[n] = (i * v0[n] + (j + 1) * v1[n] + (k - 1) * v2[n]) / depth;
  922.       }
  923.       l = sqrt(w0[0] * w0[0] + w0[1] * w0[1] + w0[2] * w0[2]);
  924.       w0[0] /= l;
  925.       w0[1] /= l;
  926.       w0[2] /= l;
  927.       l = sqrt(w1[0] * w1[0] + w1[1] * w1[1] + w1[2] * w1[2]);
  928.       w1[0] /= l;
  929.       w1[1] /= l;
  930.       w1[2] /= l;
  931.       l = sqrt(w2[0] * w2[0] + w2[1] * w2[1] + w2[2] * w2[2]);
  932.       w2[0] /= l;
  933.       w2[1] /= l;
  934.       w2[2] /= l;
  935.       recorditem(w0, w1, w2, p0, radius, shadeType, avnormal);
  936.     }
  937. }
  938.  
  939. static void drawtriangle(int i, int geomType, int depth,
  940.           GLdouble p0[3], GLdouble radius, GLenum shadeType, int avnormal)
  941. {
  942.   GLdouble *x0, *x1, *x2;
  943.  
  944.   switch (geomType) {
  945.     case 0:                                       /*
  946.                                             * icosahedron 
  947.                                             */
  948.       x0 = &idata[iindex[i][0]][0];
  949.       x1 = &idata[iindex[i][1]][0];
  950.       x2 = &idata[iindex[i][2]][0];
  951.       break;
  952.     case 1:                                       /*
  953.                                             * octahedron 
  954.                                             */
  955.       x0 = &odata[ondex[i][0]][0];
  956.       x1 = &odata[ondex[i][1]][0];
  957.       x2 = &odata[ondex[i][2]][0];
  958.       break;
  959.     case 2:                                       /*
  960.                                             * tetrahedron 
  961.                                             */
  962.       x0 = &tdata[tndex[i][0]][0];
  963.       x1 = &tdata[tndex[i][1]][0];
  964.       x2 = &tdata[tndex[i][2]][0];
  965.       break;
  966.   }
  967.   subdivide(depth, x0, x1, x2, p0, radius, shadeType, avnormal);
  968. }
  969.  
  970. static void recorditem(GLdouble * n1, GLdouble * n2, GLdouble * n3,
  971.       GLdouble center[3], GLdouble radius, GLenum shadeType, int avnormal)
  972. {
  973.   GLdouble p1[3], p2[3], p3[3], q0[3], q1[3], n11[3], n22[3], n33[3];
  974.   int i;
  975.  
  976.   for (i = 0; i < 3; i++) {
  977.     p1[i] = n1[i] * radius + center[i];
  978.     p2[i] = n2[i] * radius + center[i];
  979.     p3[i] = n3[i] * radius + center[i];
  980.   }
  981.   if (avnormal == 0) {
  982.     diff3(p1, p2, q0);
  983.     diff3(p2, p3, q1);
  984.     crossprod(q0, q1, q1);
  985.     normalize(q1);
  986.     m_xformpt(p1, p1, q1, n11);
  987.     m_xformptonly(p2, p2);
  988.     m_xformptonly(p3, p3);
  989.  
  990.     glBegin(shadeType);
  991.     glNormal3dv(n11);
  992.     glVertex3dv(p1);
  993.     glVertex3dv(p2);
  994.     glVertex3dv(p3);
  995.     glEnd();
  996.     return;
  997.   }
  998.   m_xformpt(p1, p1, n1, n11);
  999.   m_xformpt(p2, p2, n2, n22);
  1000.   m_xformpt(p3, p3, n3, n33);
  1001.  
  1002.   glBegin(shadeType);
  1003.   glNormal3dv(n11);
  1004.   glVertex3dv(p1);
  1005.   glNormal3dv(n22);
  1006.   glVertex3dv(p2);
  1007.   glNormal3dv(n33);
  1008.   glVertex3dv(p3);
  1009.   glEnd();
  1010. }
  1011.  
  1012. static GLdouble dodec[20][3];
  1013.  
  1014. static void initdodec()
  1015. {
  1016.   GLdouble alpha, beta;
  1017.  
  1018.   alpha = sqrt(2.0 / (3.0 + sqrt(5.0)));
  1019.   beta = 1.0 + sqrt(6.0 / (3.0 + sqrt(5.0)) - 2.0 + 2.0 * sqrt(2.0 / (3.0 +
  1020.                                  sqrt(5.0))));
  1021.   dodec[0][0] = -alpha;
  1022.   dodec[0][1] = 0;
  1023.   dodec[0][2] = beta;
  1024.   dodec[1][0] = alpha;
  1025.   dodec[1][1] = 0;
  1026.   dodec[1][2] = beta;
  1027.   dodec[2][0] = -1;
  1028.   dodec[2][1] = -1;
  1029.   dodec[2][2] = -1;
  1030.   dodec[3][0] = -1;
  1031.   dodec[3][1] = -1;
  1032.   dodec[3][2] = 1;
  1033.   dodec[4][0] = -1;
  1034.   dodec[4][1] = 1;
  1035.   dodec[4][2] = -1;
  1036.   dodec[5][0] = -1;
  1037.   dodec[5][1] = 1;
  1038.   dodec[5][2] = 1;
  1039.   dodec[6][0] = 1;
  1040.   dodec[6][1] = -1;
  1041.   dodec[6][2] = -1;
  1042.   dodec[7][0] = 1;
  1043.   dodec[7][1] = -1;
  1044.   dodec[7][2] = 1;
  1045.   dodec[8][0] = 1;
  1046.   dodec[8][1] = 1;
  1047.   dodec[8][2] = -1;
  1048.   dodec[9][0] = 1;
  1049.   dodec[9][1] = 1;
  1050.   dodec[9][2] = 1;
  1051.   dodec[10][0] = beta;
  1052.   dodec[10][1] = alpha;
  1053.   dodec[10][2] = 0;
  1054.   dodec[11][0] = beta;
  1055.   dodec[11][1] = -alpha;
  1056.   dodec[11][2] = 0;
  1057.   dodec[12][0] = -beta;
  1058.   dodec[12][1] = alpha;
  1059.   dodec[12][2] = 0;
  1060.   dodec[13][0] = -beta;
  1061.   dodec[13][1] = -alpha;
  1062.   dodec[13][2] = 0;
  1063.   dodec[14][0] = -alpha;
  1064.   dodec[14][1] = 0;
  1065.   dodec[14][2] = -beta;
  1066.   dodec[15][0] = alpha;
  1067.   dodec[15][1] = 0;
  1068.   dodec[15][2] = -beta;
  1069.   dodec[16][0] = 0;
  1070.   dodec[16][1] = beta;
  1071.   dodec[16][2] = alpha;
  1072.   dodec[17][0] = 0;
  1073.   dodec[17][1] = beta;
  1074.   dodec[17][2] = -alpha;
  1075.   dodec[18][0] = 0;
  1076.   dodec[18][1] = -beta;
  1077.   dodec[18][2] = alpha;
  1078.   dodec[19][0] = 0;
  1079.   dodec[19][1] = -beta;
  1080.   dodec[19][2] = -alpha;
  1081. }
  1082.  
  1083. /*
  1084.  * dodecahedron:
  1085.  * *
  1086.  * * Draws an dodecahedron with center at 0.0. The radius
  1087.  * * is sqrt(3).
  1088.  */
  1089. static void dodecahedron(GLdouble center[3], GLdouble sc, GLenum type)
  1090. {
  1091.   static int inited = 0;
  1092.  
  1093.   if (inited == 0) {
  1094.     inited = 1;
  1095.     initdodec();
  1096.   }
  1097.   m_pushmatrix();
  1098.   m_translate(center[0], center[1], center[2]);
  1099.   m_scale(sc, sc, sc);
  1100.   pentagon(0, 1, 9, 16, 5, type);
  1101.   pentagon(1, 0, 3, 18, 7, type);
  1102.   pentagon(1, 7, 11, 10, 9, type);
  1103.   pentagon(11, 7, 18, 19, 6, type);
  1104.   pentagon(8, 17, 16, 9, 10, type);
  1105.   pentagon(2, 14, 15, 6, 19, type);
  1106.   pentagon(2, 13, 12, 4, 14, type);
  1107.   pentagon(2, 19, 18, 3, 13, type);
  1108.   pentagon(3, 0, 5, 12, 13, type);
  1109.   pentagon(6, 15, 8, 10, 11, type);
  1110.   pentagon(4, 17, 8, 15, 14, type);
  1111.   pentagon(4, 12, 5, 16, 17, type);
  1112.   m_popmatrix();
  1113. }
  1114.  
  1115. static void pentagon(int a, int b, int c, int d, int e, GLenum shadeType)
  1116. {
  1117.   GLdouble n0[3], d1[3], d2[3], d3[3], d4[3], d5[3], nout[3];
  1118.  
  1119.   diff3(&dodec[a][0], &dodec[b][0], d1);
  1120.   diff3(&dodec[b][0], &dodec[c][0], d2);
  1121.   crossprod(d1, d2, n0);
  1122.   normalize(n0);
  1123.   m_xformpt(&dodec[a][0], d1, n0, nout);
  1124.   m_xformptonly(&dodec[b][0], d2);
  1125.   m_xformptonly(&dodec[c][0], d3);
  1126.   m_xformptonly(&dodec[d][0], d4);
  1127.   m_xformptonly(&dodec[e][0], d5);
  1128.  
  1129.   glBegin(shadeType);
  1130.   glNormal3dv(nout);
  1131.   glVertex3dv(d1);
  1132.   glVertex3dv(d2);
  1133.   glVertex3dv(d3);
  1134.   glVertex3dv(d4);
  1135.   glVertex3dv(d5);
  1136.   glEnd();
  1137. }
  1138.  
  1139. /*
  1140.  * linked lists--display lists for each different 
  1141.  * *    type of geometric objects.  The linked list is 
  1142.  * *    searched, until an object of the requested
  1143.  * *    size is found.  If no geometric object of that size
  1144.  * *    has been previously made, a new one is created.
  1145.  */
  1146. GLuint findList(int lindex, GLdouble * paramArray, int size)
  1147. {
  1148.   MODELPTR endList;
  1149.   int found = 0;
  1150.  
  1151.   endList = lists[lindex];
  1152.   while (endList != NULL) {
  1153.     if (compareParams(endList->params, paramArray, size))
  1154.       return (endList->list);
  1155.     endList = endList->ptr;
  1156.   }
  1157. /*
  1158.  * if not found, return 0 and calling routine should
  1159.  * *  make a new list   
  1160.  */
  1161.   return (0);
  1162. }
  1163.  
  1164. int compareParams(GLdouble * oneArray, GLdouble * twoArray, int size)
  1165. {
  1166.   int i;
  1167.   int matches = 1;
  1168.  
  1169.   for (i = 0; (i < size) && matches; i++) {
  1170.     if (*oneArray++ != *twoArray++)
  1171.       matches = 0;
  1172.   }
  1173.   return (matches);
  1174. }
  1175.  
  1176. GLuint makeModelPtr(int lindex, GLdouble * sizeArray, int count)
  1177. {
  1178.   MODELPTR newModel;
  1179.  
  1180.   newModel = (MODELPTR) malloc(sizeof(MODEL));
  1181.   newModel->list = glGenLists(1);
  1182.   newModel->numParam = count;
  1183.   newModel->params = sizeArray;
  1184.   newModel->ptr = lists[lindex];
  1185.   lists[lindex] = newModel;
  1186.  
  1187.   return (newModel->list);
  1188. }
  1189.